home *** CD-ROM | disk | FTP | other *** search
- /****************************************************************************
- * boxes.c
- *
- * This module implements the box primitive.
- * This file was written by Alexander Enzmann. He wrote the code for
- * boxes and generously provided us these enhancements.
- *
- * from Persistence of Vision Raytracer
- * Copyright 1993 Persistence of Vision Team
- *---------------------------------------------------------------------------
- * NOTICE: This source code file is provided so that users may experiment
- * with enhancements to POV-Ray and to port the software to platforms other
- * than those supported by the POV-Ray Team. There are strict rules under
- * which you are permitted to use this file. The rules are in the file
- * named POVLEGAL.DOC which should be distributed with this file. If
- * POVLEGAL.DOC is not available or for more info please contact the POV-Ray
- * Team Coordinator by leaving a message in CompuServe's Graphics Developer's
- * Forum. The latest version of POV-Ray may be found there as well.
- *
- * This program is based on the popular DKB raytracer version 2.12.
- * DKBTrace was originally written by David K. Buck.
- * DKBTrace Ver 2.0-2.12 were written by David K. Buck & Aaron A. Collins.
- *
- *****************************************************************************/
-
- #include "frame.h"
- #include "vector.h"
- #include "povproto.h"
-
- METHODS Box_Methods =
- {
- All_Box_Intersections,
- Inside_Box, Box_Normal,
- Copy_Box, Translate_Box, Rotate_Box, Scale_Box, Transform_Box,
- Invert_Box, Destroy_Box
- };
-
- extern long Ray_Box_Tests, Ray_Box_Tests_Succeeded;
-
- #define close(x, y) (fabs(x-y) < EPSILON ? 1 : 0)
-
- int All_Box_Intersections (Object, Ray, Depth_Stack)
- OBJECT *Object;
- RAY *Ray;
- ISTACK *Depth_Stack;
- {
- DBL Depth1, Depth2;
- VECTOR IPoint;
- register int Intersection_Found;
-
- Intersection_Found = FALSE;
-
- if (Intersect_Boxx (Ray, (BOX *)Object, &Depth1, &Depth2))
- {
- VScale (IPoint, Ray->Direction, Depth1);
- VAddEq (IPoint, Ray->Initial);
-
- if (Point_In_Clip (&IPoint, Object->Clip))
- {
- push_entry(Depth1,IPoint,Object,Depth_Stack);
- Intersection_Found = TRUE;
- }
-
- if (Depth2 != Depth1)
- {
- VScale (IPoint, Ray->Direction, Depth2);
- VAddEq (IPoint, Ray->Initial);
-
- if (Point_In_Clip (&IPoint, Object->Clip))
- {
- push_entry(Depth2,IPoint,Object,Depth_Stack);
- Intersection_Found = TRUE;
- }
- }
- }
- return (Intersection_Found);
- }
-
- int Intersect_Boxx (Ray, box, Depth1, Depth2)
- RAY *Ray;
- BOX *box;
- DBL *Depth1, *Depth2;
- {
- DBL t, tmin, tmax;
- VECTOR P, D;
-
- Ray_Box_Tests++;
-
- /* Transform the point into the boxes space */
- if (box->Trans != NULL)
- {
- MInvTransPoint(&P, &Ray->Initial, box->Trans);
- MInvTransDirection(&D, &Ray->Direction, box->Trans);
- }
- else
- {
- P.x = Ray->Initial.x;
- P.y = Ray->Initial.y;
- P.z = Ray->Initial.z;
- D.x = Ray->Direction.x;
- D.y = Ray->Direction.y;
- D.z = Ray->Direction.z;
- }
-
- tmin = 0.0;
- tmax = HUGE_VAL;
-
- /* Sides first */
- if (D.x < -EPSILON)
- {
- t = (box->bounds[0].x - P.x) / D.x;
- if (t < tmin)
- return 0;
- if (t <= tmax)
- tmax = t;
- t = (box->bounds[1].x - P.x) / D.x;
- if (t >= tmin)
- {
- if (t > tmax)
- return 0;
- tmin = t;
- }
- }
- else if (D.x > EPSILON)
- {
- t = (box->bounds[1].x - P.x) / D.x;
- if (t < tmin)
- return 0;
- if (t <= tmax)
- tmax = t;
- t = (box->bounds[0].x - P.x) / D.x;
- if (t >= tmin)
- {
- if (t > tmax)
- return 0;
- tmin = t;
- }
- }
- else if (P.x < box->bounds[0].x || P.x > box->bounds[1].x)
- return 0;
-
- /* Check Top/Bottom */
- if (D.y < -EPSILON)
- {
- t = (box->bounds[0].y - P.y) / D.y;
- if (t < tmin)
- return 0;
- if (t <= tmax)
- tmax = t;
- t = (box->bounds[1].y - P.y) / D.y;
- if (t >= tmin)
- {
- if (t > tmax)
- return 0;
- tmin = t;
- }
- }
- else if (D.y > EPSILON)
- {
- t = (box->bounds[1].y - P.y) / D.y;
- if (t < tmin)
- return 0;
- if (t <= tmax)
- tmax = t;
- t = (box->bounds[0].y - P.y) / D.y;
- if (t >= tmin)
- {
- if (t > tmax)
- return 0;
- tmin = t;
- }
- }
- else if (P.y < box->bounds[0].y || P.y > box->bounds[1].y)
- return 0;
-
- /* Now front/back */
- if (D.z < -EPSILON)
- {
- t = (box->bounds[0].z - P.z) / D.z;
- if (t < tmin)
- return 0;
- if (t <= tmax)
- tmax = t;
- t = (box->bounds[1].z - P.z) / D.z;
- if (t >= tmin)
- {
- if (t > tmax)
- return 0;
- tmin = t;
- }
- }
- else if (D.z > EPSILON)
- {
- t = (box->bounds[1].z - P.z) / D.z;
- if (t < tmin)
- return 0;
- if (t <= tmax)
- tmax = t;
- t = (box->bounds[0].z - P.z) / D.z;
- if (t >= tmin)
- {
- if (t > tmax)
- return 0;
- tmin = t;
- }
- }
- else if (P.z < box->bounds[0].z || P.z > box->bounds[1].z)
- return 0;
-
- *Depth1 = tmin;
- *Depth2 = tmax;
-
- /* printf("Box intersects: %g, %g\n", *Depth1, *Depth2); */
- if ((*Depth1 < Small_Tolerance) || (*Depth1 > Max_Distance))
- if ((*Depth2 < Small_Tolerance) || (*Depth2 > Max_Distance))
- return (FALSE);
- else
- *Depth1 = *Depth2;
- else
- if ((*Depth2 < Small_Tolerance) || (*Depth2 > Max_Distance))
- *Depth2 = *Depth1;
-
- Ray_Box_Tests_Succeeded++;
- return (TRUE);
- }
-
- int Inside_Box (IPoint, Object)
- VECTOR *IPoint;
- OBJECT *Object;
- {
- VECTOR New_Point;
- BOX *box = (BOX *) Object;
-
- /* Transform the point into the boxes space */
- if (box->Trans != NULL)
- MInvTransPoint(&New_Point, IPoint, box->Trans);
- else
- New_Point = *IPoint;
-
- /* Test to see if we are inside the box */
- if (New_Point.x < box->bounds[0].x || New_Point.x > box->bounds[1].x)
- return ((int) box->Inverted);
- if (New_Point.y < box->bounds[0].y || New_Point.y > box->bounds[1].y)
- return ((int) box->Inverted);
- if (New_Point.z < box->bounds[0].z || New_Point.z > box->bounds[1].z)
- return ((int)box->Inverted);
- /* Inside the box */
- return 1-box->Inverted;
- }
-
- void Box_Normal (Result, Object, IPoint)
- OBJECT *Object;
- VECTOR *Result, *IPoint;
- {
- VECTOR New_Point;
- BOX *box = (BOX *) Object;
-
- /* Transform the point into the boxes space */
- if (box->Trans != NULL)
- MInvTransPoint(&New_Point, IPoint, box->Trans);
- else
- {
- New_Point.x = IPoint->x;
- New_Point.y = IPoint->y;
- New_Point.z = IPoint->z;
- }
-
- Result->x = 0.0; Result->y = 0.0; Result->z = 0.0;
- if (close(New_Point.x, box->bounds[1].x))
- Result->x = 1.0;
- else if (close(New_Point.x, box->bounds[0].x))
- Result->x = -1.0;
- else if (close(New_Point.y, box->bounds[1].y))
- Result->y = 1.0;
- else if (close(New_Point.y, box->bounds[0].y))
- Result->y = -1.0;
- else if (close(New_Point.z, box->bounds[1].z))
- Result->z = 1.0;
- else if (close(New_Point.z, box->bounds[0].z))
- Result->z = -1.0;
- else
- {
- /* Bad result, should we do something with it? */
- Result->x = 1.0;
- }
-
- /* Transform the point into the boxes space */
- if (box->Trans != NULL)
- {
- MTransNormal(Result, Result, box->Trans);
- VNormalize(*Result, *Result);
- }
- }
-
- void *Copy_Box (Object)
- OBJECT *Object;
- {
- BOX *New;
-
- New = Create_Box();
- *New = *((BOX *) Object);
-
- New->Trans = Copy_Transform(((BOX *)Object)->Trans);
-
- return (New);
- }
-
- void Translate_Box (Object, Vector)
- OBJECT *Object;
- VECTOR *Vector;
- {
- TRANSFORM Trans;
-
- if (((BOX *)Object)->Trans == NULL)
- {
- VAddEq(((BOX *)Object)->bounds[0], *Vector);
- VAddEq(((BOX *)Object)->bounds[1], *Vector);
- Object->Bounds.Lower_Left = ((BOX *)Object)->bounds[0];
- }
- else
- {
- Compute_Translation_Transform(&Trans, Vector);
- Transform_Box(Object, &Trans);
- }
- }
-
- void Rotate_Box (Object, Vector)
- OBJECT *Object;
- VECTOR *Vector;
- {
- TRANSFORM Trans;
- Compute_Rotation_Transform(&Trans, Vector);
- Transform_Box(Object, &Trans);
- }
-
- void Scale_Box (Object, Vector)
- OBJECT *Object;
- VECTOR *Vector;
- {
- TRANSFORM Trans;
-
- if (((BOX *)Object)->Trans == NULL)
- {
- VEvaluateEq(((BOX *)Object)->bounds[0], *Vector);
- VEvaluateEq(((BOX *)Object)->bounds[1], *Vector);
- Object->Bounds.Lower_Left = ((BOX *)Object)->bounds[0];
- VSub(Object->Bounds.Lengths, ((BOX *)Object)->bounds[1],
- ((BOX *)Object)->bounds[0]);
- }
- else
- {
- Compute_Scaling_Transform(&Trans, Vector);
- Transform_Box(Object, &Trans);
- }
- }
-
- void Invert_Box (Object)
- OBJECT *Object;
- {
- ((BOX *)Object)->Inverted = 1 - ((BOX *)Object)->Inverted;
- }
-
- void Transform_Box (Object, Trans)
- OBJECT *Object;
- TRANSFORM *Trans;
- {
- BOX *box = (BOX *)Object;
- if (box->Trans == NULL)
- box->Trans = Create_Transform();
- Compose_Transforms(box->Trans, Trans);
- Object->Bounds.Lower_Left = box->bounds[0];
- VSub(Object->Bounds.Lengths, box->bounds[1], box->bounds[0]);
- recompute_bbox(&Object->Bounds, box->Trans);
- }
-
- BOX *Create_Box ()
- {
- BOX *New;
-
- if ((New = (BOX *) malloc (sizeof (BOX))) == NULL)
- MAError ("box");
-
- INIT_OBJECT_FIELDS(New, BOX_OBJECT, &Box_Methods)
-
- Make_Vector (&(New->bounds[0]), -1.0, -1.0, -1.0);
- Make_Vector (&(New->bounds[1]), 1.0, 1.0, 1.0);
- /* Recalculate the bounds */
- Make_Vector(&New->Bounds.Lower_Left, -1.0, -1.0, -1.0);
- Make_Vector(&New->Bounds.Lengths, 2.0, 2.0, 2.0);
- /* Unlike HField, we don't always have a trans here */
- New->Trans = NULL;
- New->Inverted = FALSE;
- return (New);
- }
-
- void Destroy_Box (Object)
- OBJECT *Object;
- {
- Destroy_Transform(((BOX *)Object)->Trans);
- free (Object);
- }
-